﻿// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
// Licensed under the LGPL License, Version 3.0. See License.txt in the project root for license information.
// Website: https://admin.blazor.zone

using BlazorAdmin.Caching;
using BlazorAdmin.Models;
using BlazorAdmin.Interface;
using BootstrapBlazor.Components;
using BlazorAdmin.Extensions;
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Linq;
using BlazorAdmin.Services.DbService;

namespace BlazorAdmin.Services
{
    internal class DictService : BaMgmtDbService, IDict
    {
        private const string DictServiceCacheKey = "DictService-GetAll";
        private const string K_App = "应用程序";
        private const string K_WebSettings = "网站设置";
        public DictService(IPetaPoco db) : base(db)
        {
        }

        public Dictionary<string, List<Dict>> GetByCategories(string categories)
        {
            var dic = new Dictionary<string, List<Dict>>();
            var dicts = GetAll();
            foreach (var category in categories.Split(",", StringSplitOptions.RemoveEmptyEntries))
                dic.Add(category, dicts.Where(t => t.Category == category).OrderBy(x => x.Code).ToList());

            return dic;
        }

        public List<SelectedItem> GetByCategory(string category)
        {
            var items = new List<SelectedItem>();
            GetAll().ForEach(t =>
            {
                if (t.Category == category)
                    items.Add(new SelectedItem()
                    {
                        Text = t.Name,
                        Value = t.Code
                    });
            });
            
            return items;
        }

        public List<Dict> GetAll() => CacheManager.GetOrAdd(DictServiceCacheKey, entry => Fetch<Dict>());

        public Dictionary<string, string> GetApps()
        {
            List<Dict> dicts = GetAll();
            return dicts.Where(d => d.Category == K_App).ToDictionary(d => d.Code, d => d.Name);
        }

        public List<ClientApp> GetClients()
        {
            List<Dict> dicts = GetAll();
            var values = dicts.Where(s => s.Category == K_App).ToDictionary(s => s.Name, s => s.Code);
            List<ClientApp> clients = (from kv in values select GetClient(kv.Value, dicts)).ToList();
            return clients;
        }

        public bool ExistsAppId(string appId)
        {
            var dicts = GetAll();
            return dicts.Exists(s => s.Category == K_App && s.Code == appId);
        }

        public bool SaveClient(ClientApp client)
        {
            bool result = false;
            if (string.IsNullOrEmpty(client.AppID))
                return result;

            DeleteClient(client.AppID);
            using var db = Create();
            try
            {
                db.BeginTransaction();
                var items = new List<Dict>()
                {
                    new Dict { Category = K_App, Name = client.AppName, Code = client.AppID, Define = SysEnumDictType.System },
                    new Dict { Category = client.AppID, Name ="应用首页", Code = client.HomeUrl, Define = SysEnumDictType.Customer },
                    new Dict { Category = client.AppID, Name = "网站页脚", Code = client.Footer, Define = SysEnumDictType.Customer },
                    new Dict { Category = client.AppID, Name = "网站标题", Code = client.Title, Define = SysEnumDictType.Customer },
                    new Dict { Category = client.AppID, Name = "favicon", Code = client.Favicon, Define = SysEnumDictType.Customer },
                    new Dict { Category = client.AppID, Name = "网站图标", Code = client.Icon, Define = SysEnumDictType.Customer },
                    new Dict { Category = client.AppID, Name = "个人中心地址", Code = client.ProfileUrl, Define = SysEnumDictType.Customer },
                    new Dict { Category = client.AppID, Name = "系统设置地址", Code = client.SettingsUrl, Define = SysEnumDictType.Customer },
                    new Dict { Category = client.AppID, Name = "系统通知地址", Code = client.NotificationUrl, Define = SysEnumDictType.Customer },
                    new Dict { Category = client.AppID, Name = "Jwt失效日期", Code = client.ExpiredDate.ToShortDateString(), Define = SysEnumDictType.Customer }
                };

                db.InsertBatch(items);
                db.CompleteTransaction();

                db.LogAsync("Insert");

                result = true;
            }
            catch (DbException)
            {
                db.AbortTransaction();
                throw;
            }

            return result;
        }

        public ClientApp GetClient(string appId) => GetClient(appId, default);

        public bool DeleteClient(string appId)
        {
            bool ret;
            using var db = Create();
            try
            {
                db.BeginTransaction();
                db.Execute("DELETE FROM Dicts WHERE Category = @0 AND Name = @1 AND Define = @2", "应用首页", appId, (int)SysEnumDictType.System);
                db.Execute("DELETE FROM Dicts WHERE Category = @0 AND Code = @1 AND Define = @2", K_App, appId, (int)SysEnumDictType.System);
                db.Execute("DELETE FROM Dicts WHERE Category = @Category AND Name IN (@Names)", new
                {
                    Category = appId,
                    Names = new List<string>{
                        "网站标题",
                        "网站页脚",
                        "favicon",
                        "网站图标",
                        "个人中心地址",
                        "系统设置地址",
                        "系统通知地址",
                        "Jwt失效日期",
                    }
                });
                db.CompleteTransaction();

                db.LogAsync("Delete");

                ret = true;
            }
            catch (Exception)
            {
                db.AbortTransaction();
                throw;
            }

            return ret;
        }
        /// <summary>
        /// 获取当前网站 Cookie 保持时长
        /// </summary>
        /// <returns></returns>
        public int GetCookieExpiresPeriod()
        {
            var dicts = GetAll();
            var code = dicts.FirstOrDefault(d => d.Category == K_WebSettings && d.Name == "Cookie保留时长" && d.Define == SysEnumDictType.System)?.Code ?? "0";
            _ = int.TryParse(code, out var ret);
            return ret;
        }

        private bool SaveDict(Dict dict)
        {
            using var db = Create();
            var ret = db.Update<Dict>("SET Code = @Code WHERE Category = @Category AND Name = @Name", dict) == 1;
            if (ret)
            {
                // 更新缓存
                CacheManager.Clear(DictServiceCacheKey);
            }

            db.LogAsync("Update");

            return ret;
        }

        public bool SaveCookieExpiresPeriod(int expiresPeriod) => SaveDict(new Dict { Category = K_WebSettings, Name = "Cookie保留时长", Code = expiresPeriod.ToString() });

        public string GetProfileUrl(string appId) => GetUrlByName(appId, "个人中心地址");

        public string GetSettingsUrl(string appId) => GetUrlByName(appId, "系统设置地址");

        public string GetNotificationUrl(string appId) => GetUrlByName(appId, "系统通知地址");

        private string GetUrlByName(string appId, string dictName)
        {
            string url = null;
            var dicts = GetAll();
            var appName = dicts.FirstOrDefault(d => d.Category == K_App && d.Code == appId && d.Define == SysEnumDictType.System)?.Name;
            if (!string.IsNullOrEmpty(appName))
            {
                url = dicts.FirstOrDefault(d => d.Category == appName && d.Name == dictName && d.Define == SysEnumDictType.Customer)?.Code;
            }
            return url;
        }

        /// <summary>
        /// 获取头像路径
        /// </summary>
        /// <returns></returns>
        public string GetIconFolderPath()
        {
            var dicts = GetAll();
            var path = dicts.FirstOrDefault(d => d.Name == "头像路径" && d.Category == "头像地址" && d.Define == SysEnumDictType.System)?.Code ?? "/images/uploder/";

            if (path.Contains(SysConsts.WwwRoot))
                return path;
            else
                return SysConsts.WwwRoot + path;
        }

        /// <summary>
        /// 获取头像路径
        /// </summary>
        /// <returns></returns>
        public string GetDefaultIcon()
        {
            var dicts = GetAll();
            var path = dicts.FirstOrDefault(d => d.Name == "头像文件" && d.Category == "头像地址" && d.Define == SysEnumDictType.System)?.Code ?? "default.jpg";

            if (path.Contains(SysConsts.WwwRoot))
                return path;
            else
                return $"{SysConsts.WwwRoot}/images/uploder/{path}";
        }

        /// <summary>
        /// 通过指定 appId 获得配置首页地址
        /// </summary>
        /// <param name="appId"></param>
        /// <returns></returns>
        public string GetHomeUrlByAppId(string appId)
        {
            var dicts = GetAll();
            return dicts.FirstOrDefault(d => d.Category == "应用首页" && d.Name.Equals(appId, StringComparison.OrdinalIgnoreCase) && d.Define == SysEnumDictType.System)?.Code;
        }

        public bool GetAutoLockScreen()
        {
            var dicts = GetAll();
            return dicts.FirstOrDefault(s => s.Category == K_WebSettings && s.Name == "自动锁屏" && s.Define == SysEnumDictType.System)?.Code == "1";
        }

        public bool SaveAutoLockScreen(bool value) => SaveDict(new Dict { Category = K_WebSettings, Name = "自动锁屏", Code = value ? "1" : "0" });

        public int GetAutoLockScreenInterval()
        {
            var dicts = GetAll();
            var value = dicts.FirstOrDefault(s => s.Category == K_WebSettings && s.Name == "自动锁屏时长" && s.Define == SysEnumDictType.System)?.Code ?? "0";
            _ = int.TryParse(value, out var ret);
            return ret;
        }

        public bool SaveAutoLockScreenInterval(int value) => SaveDict(new Dict { Category = K_WebSettings, Name = "自动锁屏时长", Code = value.ToString() });

        public int GetCookieExpired()
        {
            var dicts = GetAll();
            var value = dicts.FirstOrDefault(s => s.Category == K_WebSettings && s.Name == "Cookie保留时长" && s.Define == SysEnumDictType.System)?.Code ?? "0";
            _ = int.TryParse(value, out var ret);
            return ret;
        }

        public bool SaveCookieExpired(int value) => SaveDict(new Dict { Category = K_WebSettings, Name = "Cookie保留时长", Code = value.ToString() });

        public int GetExceptionExpired()
        {
            var dicts = GetAll();
            string value = dicts.FirstOrDefault(s => s.Category == K_WebSettings && s.Name == "程序异常保留时长" && s.Define == SysEnumDictType.System)?.Code ?? "0";
            _ = int.TryParse(value, out var ret);
            return ret; ;
        }

        public bool SaveExceptionExpired(int value) => SaveDict(new Dict { Category = K_WebSettings, Name = "程序异常保留时长", Code = value.ToString() });

        public int GetOperateExpired()
        {
            var dicts = GetAll();
            var value = dicts.FirstOrDefault(s => s.Category == K_WebSettings && s.Name == "操作日志保留时长" && s.Define == SysEnumDictType.System)?.Code ?? "0";
            _ = int.TryParse(value, out var ret);
            return ret; ;
        }

        public bool SaveOperateExpired(int value) => SaveDict(new Dict { Category = K_WebSettings, Name = "操作日志保留时长", Code = value.ToString() });

        public int GetLoginExpired()
        {
            var dicts = GetAll();
            var value = dicts.FirstOrDefault(s => s.Category == K_WebSettings && s.Name == "登录日志保留时长" && s.Define == SysEnumDictType.System)?.Code ?? "0";
            _ = int.TryParse(value, out var ret);
            return ret; ;
        }

        public bool SaveLoginExpired(int value) => SaveDict(new Dict { Category = K_WebSettings, Name = "登录日志保留时长", Code = value.ToString() });

        public int GetAccessExpired()
        {
            var dicts = GetAll();
            var value = dicts.FirstOrDefault(s => s.Category == K_WebSettings && s.Name == "访问日志保留时长" && s.Define == SysEnumDictType.System)?.Code ?? "0";
            _ = int.TryParse(value, out var ret);
            return ret; ;
        }

        public bool SaveAccessExpired(int value) => SaveDict(new Dict { Category = K_WebSettings, Name = "访问日志保留时长", Code = value.ToString() });

        public int GetIPCacheExpired()
        {
            var dicts = GetAll();
            var value = dicts.FirstOrDefault(s => s.Category == K_WebSettings && s.Name == "IP请求缓存时长" && s.Define == SysEnumDictType.System)?.Code ?? "0";
            _ = int.TryParse(value, out var ret);
            return ret; ;
        }

        public bool SaveIPCacheExpired(int value) => SaveDict(new Dict { Category = K_WebSettings, Name = "IP请求缓存时长", Code = value.ToString() });

        #region private methods
        private ClientApp GetClient(string appID, List<Dict> dicts = null)
        {
            dicts ??= GetAll();
            DateTime expiredDate = DateTime.MaxValue;
            string date = dicts.FirstOrDefault(s => s.Category == appID && s.Name == "Jwt失效日期")?.Code;
            _ = DateTime.TryParse(date, out expiredDate);
            ClientApp clientInfo = new()
            {
                AppID = appID,
                AppName = dicts.FirstOrDefault(s => s.Category == K_App && s.Code == appID)?.Name,
                HomeUrl = dicts.FirstOrDefault(s => s.Category == "应用首页" && s.Name == appID)?.Code,
                ProfileUrl = dicts.FirstOrDefault(s => s.Category == appID && s.Name == "个人中心地址")?.Code,
                SettingsUrl = dicts.FirstOrDefault(s => s.Category == appID && s.Name == "系统设置地址")?.Code,
                NotificationUrl = dicts.FirstOrDefault(s => s.Category == appID && s.Name == "系统通知地址")?.Code,
                Title = dicts.FirstOrDefault(s => s.Category == appID && s.Name == "网站标题")?.Code,
                Footer = dicts.FirstOrDefault(s => s.Category == appID && s.Name == "网站页脚")?.Code,
                Icon = dicts.FirstOrDefault(s => s.Category == appID && s.Name == "网站图标")?.Code,
                Favicon = dicts.FirstOrDefault(s => s.Category == appID && s.Name == "favicon")?.Code,
                ExpiredDate = expiredDate
            };
            return clientInfo;
        }

        public bool SaveDicts(List<Dict> insertDicts, List<Dict> updateDicts)
        {
            using var db = Create();
            //if (insertDicts.Count > 0)
            //    db.InsertBatch(insertDicts);
            insertDicts.ForEach(t => db.Insert(t));

            if (updateDicts.Count > 0)
            {
                Dict? dict;
                var dicts = GetAll();
                updateDicts.ForEach(t =>
                {
                    db.Update(t);
                    dict = dicts.FirstOrDefault(d => d.Category == t.Category && d.Code == t.Code);
                    dict.Name = t.Name;
                });
            }

            return true;
        }

        #endregion
    }
}